#include "base/core/os/debug.h"
#include <errno.h>
#include <stdlib.h>
#include <execinfo.h>
#include <string.h>
#include <string>
#include "base/core/os/file.h"
#include "base/core/os/directory.h"
#include "base/core/os/thread.h"
#include "base/core/os/string.h"
#include "base/core/com_define.h"

const char SetBackgroundColor_Red[] = "\033[41m\033[37m";
const char SetBackgroundColor_Green[] = "\033[42m\033[37m";
const char SetBackgroundColor_Yellow[] = "\033[43m\033[30m";
const char SetFontColor_Green[] = "\033[32m\033[40m";
const char SetFontColor_Yellow[] = "\033[1;33m";
const char ResetConsolasStyle[] = "\033[0m";

int ErrorNO() 
{
	return errno;  // errno is thread-local
}

void SetErrorNO(int err_no) 
{
	errno = err_no;
}

char* ErrorMsg(int err_no, char *buf, size_t len) 
{
	MMO_ASSERT(buf);
	MMO_ASSERT(len > 0);

	strerror_r(err_no, buf, len);
	return buf;
}

static File * OpenDumpFile(const char *path) 
{
	std::string file_path(path);
	std::string::size_type segment_offset = file_path.rfind(MMO_PATH_SEPRATOR);
	if (segment_offset != file_path.npos) 
	{
		std::string  file_directory = file_path.substr(0, segment_offset);
		if (!PathIsExist(file_directory.c_str()) && 
			!MakeDirectory(file_directory.c_str())) 
		{
			return NULL;
		}
	}
	return FileOpen(path, "a");
}

// 输出信息到控制台窗口和 IDE 调试窗口
void OutputToConsole(const char * info) 
{
	MMO_ASSERT(info);
	if (info == NULL) return;

	if (strstr(info, "ERROR") > 0)
	{
		fprintf(stdout, SetBackgroundColor_Red);
	}
	else if (strstr(info, "WARNING"))
	{
		fprintf(stdout, SetFontColor_Yellow);
	}
	else
	{
		fprintf(stdout, SetFontColor_Green);
	}

	fprintf(stdout, "%s\n", info);
	fprintf(stdout, "\r\n%s", ResetConsolasStyle);
}

bool OutputFmtToConsole(const char * format, ...) 
{
	bool result = false;
	int ret = -1;
	va_list args;

	MMOLOG_ASSERT_EXIT (format);

	if (format == NULL) goto Exit0;

	if (strstr(format, "ERROR") > 0)
	{
		fprintf(stdout, SetBackgroundColor_Red);
	} 
	else if (strstr(format, " fail") > 0)
	{
		fprintf(stdout, SetBackgroundColor_Yellow);
	} 
	else
	{
		fprintf(stdout, SetFontColor_Green);
	}
	// 字符串写
	va_start(args, format);
	ret = vfprintf(stdout, format, args);
	va_end(args);

	fprintf(stdout, "\r\n%s", ResetConsolasStyle);
	if (ret == -1) goto Exit0;

	result = true;
Exit0:      
  return result;
}

// 生成 dump 文件(Linux使用)
void WriteDump(const char * file_path, const char * sig_info) 
{
	MMO_ASSERT(file_path);
	if (!file_path) return;

	void * dump_array[32];
	int size = backtrace(dump_array, 32);
	char ** symbols = backtrace_symbols(dump_array, size);
	if (symbols) 
	{
		if (size > 10) size = 10;
		if (size > 0) 
		{
			File *file;
			if ((file = OpenDumpFile(file_path)) == NULL) 
			{
				free(symbols);
				return;
			}
			char thread_info[256] = { 0 };
			snprintf(thread_info, sizeof(thread_info),
					"thread[%d] cause dump\r\n", ThreadId());
			file->Write(thread_info, strlen(thread_info));
			if (sig_info) file->Write(sig_info, strlen(sig_info));
			for (int i = 0; i < size; ++i) 
			{
				printf("%s\r\n", symbols[i]);
				file->Write(symbols[i], strlen(symbols[i]));
				file->Write("\r\n", 2);
			}
			FileClose(file);
		}
		free(symbols);
	} 
	else 
	{
		File *file;
		if ((file = OpenDumpFile(file_path)) == NULL) return;
		char thread_info[256] = { 0 };
		snprintf(thread_info, sizeof(thread_info),
					"thread[%d] cause dump\r\n", ThreadId());
		file->Write(thread_info, strlen(thread_info));

		if (sig_info) file->Write(sig_info, strlen(sig_info));
		FileClose(file);
	}
}
